/** * Container - Container for Mapper XML Components * * Copyright (c) 2002 * Marty Phelan, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.taursys.xml; import java.util.ArrayList; import java.util.EventObject; import com.taursys.dom.DocumentAdapter; import java.util.Iterator; import com.taursys.xml.event.*; import java.util.HashMap; /** * <p>This class is a foundation container for MapperXML components. This class * defines all required properties and methods for a container and provides * basic implementation for many of them. The <code>Container</code> provides * 3 primary functions:</p> * <ul> * <li><code>Component</code> management - provides methods to add, remove and * retrieve <code>Components</code>. * </li> * <li>Provide access to a <code>DocumentAdapter</code> for the * <code>Components</code> to render themselves to. This implementation simply * looks to its parent <code>Container</code> to obtain the * <code>DocumentAdapter</code>. Bottom level or master <code>Containers</code> * should override this method and provide access to a * <code>DocumentAdapter</code>. * </li> * <li>Provide access to <code>Dispatchers</code> for the various event types * to the <code>Components</code>. This is done through the * <code>getDispatcher</code> method which takes the fully qualified class * name of the Event. <code>Components</code> need to access these * <code>Dispatchers</code> whenever they are added or removed from this * <code>Container</code> so they can add or remove themselves * from the various event notification lists. This provides an internal * <code>HashMap</code> of <code>Dispatchers</code> which are keyed by * their fully qualified event name. Implementations can maintain their own * <code>Dispatchers</code> using the <code>add/removeDispatcher</code> * methods. * </li> * </ul> */ public abstract class Container extends Component { private ArrayList components = new ArrayList(); private HashMap dispatchers = new HashMap(); /** * Constructs a new container */ public Container() { } // ========================================================================= // Methods to Manage Components for this Container // ========================================================================= /** * Add a component to this container. No action is taken if the component * already belongs to this container. If the component belongs to another * container as indicated by its parent, it is first removed from the old * container before it is added to this container. Finally, it is added to * this container and its parent is set to this container. The component's * addNotify method is also invoked so it will be notified of events it is * interested in. */ public void add(Component c) { if (!components.contains(c)) { // remove from old parent if (c.parent != null) c.parent.remove(c); // Add to this container, set parent and setup component to be notified components.add(c); c.parent = this; c.addNotify(); } } /** * Removes the given component from this container and sets its parent to null. * Also invokes removeNotify on the given component so it will un-register * itself with any dispatchers. */ public void remove(Component c) { c.removeNotify(); components.remove(c); c.parent = null; } /** * Recursively searches for given Component and returns true if found. * @param c Component to look for * @return true if found in this container or a child container */ public boolean contains(Component c) { // Check our children first if (components.contains(c)) return true; // recurse child containers Iterator iter = components.iterator(); while (iter.hasNext()) { Object item = iter.next(); if (item instanceof Container) { if (((Container)item).contains(c)) return true; } } return false; } /** * Recursively searches for a DocumentComponent with the given ID. * Returns DocumentComponent if found else null. * Returns null if given id is null * @param id the ID to search for * @return the DocumentComponent if found else null */ public DocumentComponent get(String id) { if (id == null) return null; Iterator iter = components.iterator(); while (iter.hasNext()) { Object item = iter.next(); if (item instanceof DocumentComponent) if (id.equals(((DocumentComponent)item).getId())) return (DocumentComponent)item; if (item instanceof Container) { DocumentComponent dc = ((Container)item).get(id); if (dc != null) return dc; } } return null; } /** * Returns an array of all the components for this container. */ public Component[] getComponents() { return (Component[])components.toArray(new Component[]{}); } // ========================================================================= // Methods to Access Document Adapter // ========================================================================= /** * Returns the DocumentAdapter from the parent else null if no parent. * The master container should override this method to return the shared * DocumentAdapter for all components. */ public DocumentAdapter getDocumentAdapter() { if (this.parent != null) return parent.getDocumentAdapter(); else return null; } // ========================================================================= // Methods to Add/Remove/Get Dispatchers // ========================================================================= /** * Add the given <code>Dispatcher</code> for the given <code>eventType</code> * to this <code>Container</code>. * @param eventType fully qualified class name of the Event * @param d the <code>Dispatcher</code> for this event type */ public void addDispatcher(String eventType, Dispatcher d) { dispatchers.put(eventType, d); } /** * Remove the <code>Dispatcher</code> for the given <code>eventType</code> * from this <code>Container</code>. * @param eventType fully qualified class name of the Event */ public void removeDispatcher(String eventType) { dispatchers.remove(eventType); } /** * Get the <code>Dispatcher</code> for the given <code>eventType</code>. * The <code>eventType</code> is the fully qualified class name of the Event * which that <code>Dispatcher</code> dispatches. This method first looks * for the <code>Dispatcher</code> in its set of <code>Dispatchers</code>. * If not found, it invokes its parent <code>Container</code>'s * <code>getDispatcher</code>. If this <code>Container</code>'s has no * parent, it returns null. * @param eventType fully qualified class name of the Event * @return the requested <code>Dispatcher</code> or null if not found. */ public Dispatcher getDispatcher(String eventType) { Dispatcher d = (Dispatcher)dispatchers.get(eventType); if (d == null && parent != null) d = parent.getDispatcher(eventType); return d; } // ========================================================================= // DEPRECATED Methods to Access Dispatchers // ========================================================================= /** * Returns the Dispatcher for ParameterEvents from the parent else null if no parent. * The master container should override this method to return the shared * Dispatcher for all components. * @deprecated use getDispatcher(String eventType) instead. This will be * removed in the future. */ public Dispatcher getParameterDispatcher() { return getDispatcher(ParameterEvent.class.getName()); } /** * Returns the Dispatcher for InputEvents from the parent else null if no parent. * The master container should override this method to return the shared * Dispatcher for all components. * @deprecated use getDispatcher(String eventType) instead. This will be * removed in the future. */ public Dispatcher getInputDispatcher() { return getDispatcher(InputEvent.class.getName()); } /** * Returns the Dispatcher for TriggerEvents from the parent else null if no parent. * The master container should override this method to return the shared * Dispatcher for all components. * @deprecated use getDispatcher(String eventType) instead. This will be * removed in the future. */ public Dispatcher getTriggerDispatcher() { return getDispatcher(TriggerEvent.class.getName()); } /** * Returns the Dispatcher for RenderEvents from the parent else null if no parent. * The master container should override this method to return the shared * Dispatcher for all components. * @deprecated use getDispatcher(String eventType) instead. This will be * removed in the future. */ public RenderDispatcher getRenderDispatcher() { return (RenderDispatcher)getDispatcher(RenderEvent.class.getName()); } /** * Returns the Dispatcher for RecycleEvents from the parent else null if no parent. * The master container should override this method to return the shared * Dispatcher for all components. * @deprecated use getDispatcher(String eventType) instead. This will be * removed in the future. */ public RecycleDispatcher getRecycleDispatcher() { return (RecycleDispatcher)getDispatcher(RecycleEvent.class.getName()); } }